package com.platform.common.secret.service;

import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONArray;
import com.platform.common.core.constant.CacheConstants;
import com.platform.common.core.domain.R;
import com.platform.common.core.utils.StringUtils;
import com.platform.common.redis.service.RedisService;
import com.platform.common.secret.domain.AppParam;
import com.platform.common.secret.utils.*;
import com.platform.common.secret.utils.sm2.Sm2Util;
import com.platform.common.secret.utils.sm4.SM4Utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.function.Function;

/**
 * @author yzg
 * @date 2023/4/18
 * @apiNote
 */
@Slf4j
//@Service
@Component
public class SecretEncryptService {
    @Resource
    private RedisService redisService;

    private Boolean enable=true;
    /**
     * 专用解码
     * @param param
     * @return
     */
    public <T> Object decode(AppParam param, Class<T> beanClass) {
        //获取加密工具类
        String apiUrl=param.getApiUrl();
        String appKey=param.getAppKey();
        Object data=param.getMsgData();
        String result = JSONUtil.toJsonStr(data);
        String value = redisService.getCacheObject(CacheConstants.API_SEC_KEY +appKey+"_"+apiUrl);
        if(value==null||value==""|| StringUtils.isEmpty(value)){
            throw new RuntimeException("获取接口信息失败");
        }
        //加密工具的 code
        String secretCode=value.split(";")[2];
        //应用秘钥（非对称时 替代私钥）（对称加密 替代秘钥）（PRE 作为秘钥）
        String apiPrivateSecret=value.split(";")[1];
        //应用(非对称时 替代公钥)（秘钥作为 口令）
        String apiPublicSecret=value.split(";")[0];

        try {
            switch (secretCode){
                case "SM2":{
                    result= Sm2Util.decrypt(URLDecoder.decode(result.toString(), "UTF-8"),apiPrivateSecret);

                }; break;
                case "SM4":{
                    //对称加密——使用应用秘钥作为私钥
                    SM4Utils sm4Utils=new SM4Utils();
                    sm4Utils.secretKey=apiPrivateSecret;
                    result= sm4Utils.decryptData_ECB(URLDecoder.decode(result.toString(), "UTF-8"));

                };break;
                case "DES":{
                    DesUtil desUtil=new DesUtil(apiPrivateSecret);
                    result= desUtil.getDesString(URLDecoder.decode(result.toString(), "UTF-8"));
                }
                break;
                case "AES":{
                    result= AESECBUtil.Decrypt(URLDecoder.decode(result.toString(), "UTF-8"),apiPrivateSecret);
                };break;
                case "RSA":{
                    result= RSAUtils.decryptByPrivateKey(URLDecoder.decode(result.toString(), "UTF-8"),apiPrivateSecret);

                };break;
                case "PBE":{
                    byte[] salt=apiPublicSecret.getBytes(StandardCharsets.ISO_8859_1);
                    result=PBEUtil.decrypt(URLDecoder.decode(result.toString(), "UTF-8"),apiPrivateSecret,salt);
//                    byte[] decryptData=PBEUtil.decrypt(result.getBytes(StandardCharsets.ISO_8859_1),apiPrivateSecret,salt);
//                    result=new String(decryptData);
                };break;
                case "BASE64":{
                    byte[] decryptData=Base64Util.decryBASE64(result);
                    result=new String(decryptData, StandardCharsets.UTF_8);
                };break;
                default:
                    throw new RuntimeException("不支持指定加密工具");
            }
        }catch (Exception e){
            log.error("decrypt解码错误:{}", e);
        }
        if(result.startsWith("[") && result.endsWith("]")){
            //解密后是 集合
            JSONArray jsonArray = JSONArray.parseArray(result) ;
            List<T> list=jsonArray.toJavaList(beanClass);
            return list;
        }else  if(result.startsWith("{") && result.endsWith("}")){
            //解密后是单个实体
            T t = JSONUtil.toBean(result, beanClass);
            return t;
        }else {
            log.error("decrypt解码错误:{}");
            return null;
        }

    }

    /**
     * 单纯解密
     * @param
     * @return
     */
    public String onlyDecode( Object data, String appKey,String apiUrl) {
        //获取加密工具类
        String result = JSONUtil.toJsonStr(data);
        String value = redisService.getCacheObject(CacheConstants.API_SEC_KEY +appKey+"_"+apiUrl);
        if(value==null||value==""|| StringUtils.isEmpty(value)){
            throw new RuntimeException("获取接口信息失败");
        }
        //加密工具的 code
        String secretCode=value.split(";")[2];
        //应用秘钥（非对称时 替代私钥）（对称加密 替代秘钥）（PRE 作为秘钥）
        String apiPrivateSecret=value.split(";")[1];
        //应用(非对称时 替代公钥)（秘钥作为 口令）
        String apiPublicSecret=value.split(";")[0];

        try {
            switch (secretCode){
                case "SM2":{
                    result= Sm2Util.decrypt(URLDecoder.decode(result.toString(), "UTF-8"),apiPrivateSecret);

                }; break;
                case "SM4":{
                    //对称加密——使用应用秘钥作为私钥
                    SM4Utils sm4Utils=new SM4Utils();
                    sm4Utils.secretKey=apiPrivateSecret;
                    result= sm4Utils.decryptData_ECB(URLDecoder.decode(result.toString(), "UTF-8"));

                };break;
                case "DES":{
                    DesUtil desUtil=new DesUtil(apiPrivateSecret);
                    result= desUtil.getDesString(URLDecoder.decode(result.toString(), "UTF-8"));
                }
                break;
                case "AES":{
                    result= AESECBUtil.Decrypt(URLDecoder.decode(result.toString(), "UTF-8"),apiPrivateSecret);
                };break;
                case "RSA":{
                    result= RSAUtils.decryptByPrivateKey(URLDecoder.decode(result.toString(), "UTF-8"),apiPrivateSecret);

                };break;
                case "PBE":{
                    byte[] salt=apiPublicSecret.getBytes(StandardCharsets.ISO_8859_1);
                    result=PBEUtil.decrypt(URLDecoder.decode(result.toString(), "UTF-8"),apiPrivateSecret,salt);
//                    byte[] decryptData=PBEUtil.decrypt(result.getBytes(StandardCharsets.ISO_8859_1),apiPrivateSecret,salt);
//                    result=new String(decryptData);
                };break;
                case "BASE64":{
                    byte[] decryptData=Base64Util.decryBASE64(result);
                    result=new String(decryptData, StandardCharsets.UTF_8);
                };break;
                default:
                    throw new RuntimeException("不支持指定加密工具");
            }
        }catch (Exception e){
            log.error("decrypt解码错误:{}", e);
        }
        if (result == null) {
            result = "";
        }
//        if(result.startsWith("[") && result.endsWith("]")){
//            //解密后是 集合
//            JSONArray jsonArray = JSONArray.parseArray(result) ;
//            List<T> list=jsonArray.toJavaList(beanClass);
//            return list;
//        }else  if(result.startsWith("{") && result.endsWith("}")){
//            //解密后是单个实体
//            T t = JSONUtil.toBean(result, beanClass);
//            return t;
//        }else {
//            log.error("decrypt解码错误:{}");
//            return null;
//        }
        try {
            return result;
        } catch (Exception e) {
            log.error("URLEncoder编码错误:{}", data);
            return null;
        }
    }
    /**
     *  专用加密编码
     * @param obj 加密数据
     * @param returnFun 返回体
     * @param apiUrl 接口路径
     * @return
     */
    public R encode(Object obj, Function<Object, R> returnFun,String appKey,String apiUrl) {
        if (!enable) {
            return returnFun.apply(obj);
        }

        String data = obj == null ? "{}" : JSONUtil.toJsonStr(obj);
        String result = JSONUtil.toJsonStr(data);

        String value = redisService.getCacheObject(CacheConstants.API_SEC_KEY +appKey+"_"+apiUrl);
        if(value==null||value==""|| StringUtils.isEmpty(value)){
            throw new RuntimeException("获取接口信息失败");
        }
        //加密工具的 code
        String secretCode=value.split(";")[2];
        //应用秘钥（非对称时 替代私钥）（对称加密 替代秘钥）（PRE 作为秘钥）
        String apiPrivateSecret=value.split(";")[1];
        //应用(非对称时 替代公钥)（秘钥作为 口令）
        String apiPublicSecret=value.split(";")[0];

        try {
            switch (secretCode){
                case "SM2":{
                    //公钥加密
                    result= Sm2Util.encrypt(URLDecoder.decode(data.toString(), "UTF-8"),apiPublicSecret);

                }; break;
                case "SM4":{
                    //对称加密——使用应用秘钥作为私钥
                    SM4Utils sm4Utils=new SM4Utils();
                    sm4Utils.secretKey=apiPrivateSecret;
                    result= sm4Utils.encryptData_ECB(URLDecoder.decode(data.toString(), "UTF-8"));

                };break;
                case "DES":{
                    DesUtil desUtil=new DesUtil(apiPrivateSecret);
                    result= desUtil.getEncString(URLDecoder.decode(data.toString(), "UTF-8"));
                }
                break;
                case "AES":{
                    result= AESECBUtil.Encrypt(URLDecoder.decode(data.toString(), "UTF-8"),apiPrivateSecret);
                };break;
                case "RSA":{
                    result= RSAUtils.encryptByPublicKey(URLDecoder.decode(data.toString(), "UTF-8"),apiPublicSecret);

                };break;
                case "PBE":{
                    byte[] salt=apiPublicSecret.getBytes(StandardCharsets.ISO_8859_1);
                    result=PBEUtil.encrypt(URLDecoder.decode(data.toString(), "UTF-8"),apiPrivateSecret,salt);
//                    byte[] encryptData=PBEUtil.encrypt(data.getBytes(),apiPrivateSecret,salt);
//                    result=new String(encryptData,StandardCharsets.ISO_8859_1);

                };break;
                case "BASE64":{
                    byte[] encrypt=result.getBytes(StandardCharsets.UTF_8);
                    result=Base64Util.encryptBASE64(encrypt);
                };break;
                default:
                    throw new RuntimeException("不支持指定加密工具");
            }
        }catch (Exception e){
            log.error("加密错误:{}", e);
        }
        if (result == null) {
            result = "";
        }
        try {
            return returnFun.apply(URLEncoder.encode(result,"UTF-8"));
        } catch (Exception e) {
            log.error("URLEncoder编码错误:{}", data);
            return R.fail("encode error");
        }
    }


    /**
     *  单纯加密
     * @param obj 加密数据
     * @param apiUrl 接口路径
     * @return
     */
    public String onlyEncode(Object obj,String appKey,String apiUrl) {


        String data = obj == null ? "{}" : JSONUtil.toJsonStr(obj);
        String result = JSONUtil.toJsonStr(data);

        String value = redisService.getCacheObject(CacheConstants.API_SEC_KEY +appKey+"_"+apiUrl);
        if(value==null||value==""|| StringUtils.isEmpty(value)){
            throw new RuntimeException("获取接口信息失败");
        }
        //加密工具的 code
        String secretCode=value.split(";")[2];
        //应用秘钥（非对称时 替代私钥）（对称加密 替代秘钥）（PRE 作为秘钥）
        String apiPrivateSecret=value.split(";")[1];
        //应用(非对称时 替代公钥)（秘钥作为 口令）
        String apiPublicSecret=value.split(";")[0];

        try {
            switch (secretCode){
                case "SM2":{
                    //公钥加密
                    result= Sm2Util.encrypt(URLDecoder.decode(data.toString(), "UTF-8"),apiPublicSecret);

                }; break;
                case "SM4":{
                    //对称加密——使用应用秘钥作为私钥
                    SM4Utils sm4Utils=new SM4Utils();
                    sm4Utils.secretKey=apiPrivateSecret;
                    result= sm4Utils.encryptData_ECB(URLDecoder.decode(data.toString(), "UTF-8"));

                };break;
                case "DES":{
                    DesUtil desUtil=new DesUtil(apiPrivateSecret);
                    result= desUtil.getEncString(URLDecoder.decode(data.toString(), "UTF-8"));
                }
                break;
                case "AES":{
                    result= AESECBUtil.Encrypt(URLDecoder.decode(data.toString(), "UTF-8"),apiPrivateSecret);
                };break;
                case "RSA":{
                    result= RSAUtils.encryptByPublicKey(URLDecoder.decode(data.toString(), "UTF-8"),apiPublicSecret);

                };break;
                case "PBE":{
                    byte[] salt=apiPublicSecret.getBytes(StandardCharsets.ISO_8859_1);
                    result=PBEUtil.encrypt(URLDecoder.decode(data.toString(), "UTF-8"),apiPrivateSecret,salt);
//                    byte[] encryptData=PBEUtil.encrypt(data.getBytes(),apiPrivateSecret,salt);
//                    result=new String(encryptData,StandardCharsets.ISO_8859_1);

                };break;
                case "BASE64":{
                    byte[] encrypt=result.getBytes(StandardCharsets.UTF_8);
                    result=Base64Util.encryptBASE64(encrypt);
                };break;
                default:
                    throw new RuntimeException("不支持指定加密工具");
            }
        }catch (Exception e){
            log.error("加密错误:{}", e);
        }
        if (result == null) {
            result = "";
        }
        try {
            return URLEncoder.encode(result,"UTF-8");
        } catch (Exception e) {
            log.error("URLEncoder编码错误:{}", data);
            return null;
        }
    }

    public static void main(String[] args)throws Exception {



        String s="eyJ0Y29kZSI6IlNNU18yMTExMTExMTEiLCJtc2dUeXBlIjoiMiIsInNlbmRlciI6Iuiwg+eUqOaWuSIsIm1zZ1BhcmFtcyI6eyJtb250aCI6IjfmnIgiLCJlbnRlcnByaXNlIjoi56ys5LiJ5pa555+t5L+h6LCD55So5pa55pyJ6ZmQ5YWs5Y+4In0sIm1zZ1JlY2VpdmVyIjoiMTg3Mzg2OTM1OTAifQ==";
        String result=s.toString();
        byte[] decryptData=Base64Util.decryBASE64(result);
        result=new String(decryptData, StandardCharsets.UTF_8);
        System.out.println(result);
    }

}
